# Use Variables

## Business Background

In Workflow orchestration, information needs to be passed between nodes. To achieve this, we use **variables** to store and manage this information.

:::warning A variable consists of three main parts:

1. **Unique Identifier**: The name of the variable, used to distinguish different variables so that they can be accurately referenced and used in the program. For example: `userName` or `totalAmount`.
2. **Value**: The data stored by the variable. The value can be of various types, such as numbers (e.g., `42`), strings (e.g., `"Hello!"`), boolean values (e.g., `true`), etc.
3. **Type**: The kind of data that the variable can store. The type determines what kind of values the variable can accept. For example, a variable can be an integer, float, string, or boolean, etc.

:::

Here is an example of a workflow orchestration: The WebSearch node retrieves knowledge and passes it to the LLM node for analysis through the `natural_language_desc`.

<div style={{display: 'flex', gap: '20px'}}>
  <img style={{width: "50%"}} loading="lazy" src="/variable/variable-biz-context-websearch-llm.png" />
  <div>
    In this example:
    <p style={{marginTop: 10}}>1. The WebSearch node stores the information (value) in a variable with the unique identifier `natural_language_desc`.</p>
    <p style={{marginTop: 5}}>2. The LLM node retrieves the information (value) from the knowledge base using the unique identifier `natural_language_desc` and passes it to the LLM node for analysis.</p>
    <p style={{marginTop: 5}}>3. The type of the `natural_language_desc` variable is a string, representing the content of the information retrieved from the web, such as "DeepSeek has released a new model today."</p>
  </div>
</div>

## What is the Variable Engine?

The Variable Engine is an optional built-in feature provided by Flowgram that helps to efficiently implement **variable information orchestration** during workflow design. It can achieve the following functions:

<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "25px" }}>
  <div style={{ gridColumn: "span 2" }}>
    <b>Scope Constraint Control</b>
    <p className="rs-tip">With the Variable Engine, you can control the scope of variables, ensuring that variables are available within the appropriate range and avoiding unnecessary conflicts.</p>
    <div style={{display: "flex", gap: "25px"}}>
      <div>
        <img loading="lazy" src="/variable/variable-scope-feature-1.png" />
        <p style={{marginTop: '10px'}}>In the image, the query variable of the Start node can be accessed by the subsequent LLM node and End node.</p>
      </div>
      <div>
        <img loading="lazy" src="/variable/variable-scope-feature-2.png" />
        <p style={{marginTop: '10px'}}>In the image, the LLM node is within the Condition branch, while the End node is outside the Condition branch; therefore, the variable selector of the End node cannot select the result variable from the LLM node.</p>
      </div>
    </div>
  </div>
  <div>
    <b>Maintenance of Variable Information Tree</b>
    <p className="rs-tip">The Variable Engine can help you build a clear variable information tree, making it easier to view and manage the status and relationships of all variables.</p>
    <img loading="lazy" src="/variable/variable-tree-management.gif" />
    <p style={{marginTop: '10px'}}>The image shows multiple nodes + global configuration output variables; some variables contain multiple sub-variables, forming a tree structure.</p>
  </div>
  <div>
    <b>Automatic Type Inference of Variables</b>
    <p className="rs-tip">The Variable Engine can automatically infer the type of variables based on context, reducing the workload of manually specifying types and improving development efficiency.</p>
    <img loading="lazy" src="/variable/variable-batch-auto-infer.gif" />
    <p style={{marginTop: '10px'}}>In the image, the Batch node processes the arr variable from the Start node; when the type of the arr variable changes, the type of the item variable output by the Batch node also changes accordingly.</p>
  </div>
</div>

## Enable Variable Engine

[> API Detail](https://flowgram.ai/auto-docs/editor/interfaces/VariablePluginOptions.html)

```tsx pure title="use-editor-props.ts" {3}

// EditorProps
{
  variableEngine: {
    /**
     * Need to enable the variable engine to use
     */
    enable: true
  }
}
```

## Node Output Variables

[> Demo Detail](https://github.com/bytedance/flowgram.ai/blob/main/apps/demo-fixed-layout/src/plugins/sync-variable-plugin/sync-variable-plugin.ts#L25)

### Set Output Variables through FlowNodeVariableData

```tsx pure title="sync-variable-plugin.tsx"
import {
  FlowNodeVariableData,
  ASTFactory,
} from '@flowgram.ai/fixed-layout-editor';

// ....

flowDocument.onNodeCreate(({ node }) => {
  const variableData = node.getData<FlowNodeVariableData>(FlowNodeVariableData);

  // ....

  // 1. Clear VariableData if No value
  variableData.clearVar()

  // 2. Set a String Variable as output
  variableData.setVar(
    ASTFactory.createVariableDeclaration({
      meta: {
        title: `Your Output Variable Title`,
      },
      key: `your_variable_global_unique_key_${node.id}`,
      type: ASTFactory.createString(),
    })
  )

  // 3. Set a Complicated Variable Data as output
  variableData.setVar(
    ASTFactory.createVariableDeclaration({
      meta: {
        title: `Your Output Variable Title`,
      },
      key: `your_variable_global_unique_key_${node.id}`,
      type: ASTFactory.createArray({
        items: ASTFactory.createObject({
          properties: [
            ASTFactory.createProperty({
              key: 'stringType',
              type: ASTFactory.createString(),
            }),
            ASTFactory.createProperty({
              key: 'booleanType',
              type: ASTFactory.createBoolean(),
            }),
            ASTFactory.createProperty({
              key: 'numberType',
              type: ASTFactory.createNumber(),
            }),
            ASTFactory.createProperty({
              key: 'integerType',
              type: ASTFactory.createInteger(),
            }),
          ],
        }),
      }),
    })
  );

  // ....
})

// ....

```

More usage, see: [Class: FlowNodeVariableData](https://flowgram.ai/auto-docs/editor/classes/FlowNodeVariableData.html)

### Set Output Variables through Form Effect


```tsx pure title="node-registries.ts"
import {
  FlowNodeRegistry,
  createEffectFromVariableProvider,
  ASTFactory,
  type ASTNodeJSON
} from '@flowgram.ai/fixed-layout-editor';

export function createTypeFromValue(value: string): ASTNodeJSON | undefined {
  switch (value) {
    case 'string':
      return ASTFactory.createString();
    case 'number':
      return ASTFactory.createNumber();
    case 'boolean':
      return ASTFactory.createBoolean();
    case 'integer':
      return ASTFactory.createInteger();

    default:
      return;
  }
}

export const nodeRegistries: FlowNodeRegistry[] = [
  {
    type: 'start',
    formMeta: {
      effect: {
        'path.to.value': createEffectFromVariableProvider({
          // parse form value to variable
          parse(v: string) {
            return {
              meta: {
                title: `Your Output Variable Title`,
              },
              key: `your_variable_global_unique_key_${node.id}`,
              type: createTypeFromValue(v)
            }
          }
        }),
      },
      render: () => (
       // ...
      )
    },
  }
]

```


## Node Consumes Variables

### Get Variable List

```tsx pure title="use-variable-tree.tsx"
import {
  type BaseVariableField,
  useScopeAvailable,
} from '@flowgram.ai/fixed-layout-editor';

// .... Inside react hooks or component

const available = useScopeAvailable()

const renderVariable = (variable: BaseVariableField) => {
  // ....
}

return available.variables.map(renderVariable)

// ....


```

### Get Drilldown of Object Type Variable

```tsx pure title="use-variable-tree.tsx"
import {
  type BaseVariableField,
  ASTMatch,
} from '@flowgram.ai/fixed-layout-editor';

// ....

const renderVariable = (variable: BaseVariableField) => ({
  title: variable.meta?.title,
  key: variable.key,
  // Only Object Type can drilldown
  children: ASTMatch.isObject(type) ? type.properties.map(renderVariable) : [],
});

// ....

```

### Get Drilldown of Array Type Variable

```tsx pure title="use-variable-tree.tsx"
import {
  type BaseVariableField,
  type BaseType,
  ASTMatch,
} from '@flowgram.ai/fixed-layout-editor';

// ....

const getTypeChildren = (type?: BaseType): BaseVariableField[] => {
  if (!type) return [];

  // get properties of Object
  if (ASTMatch.isObject(type)) return type.properties;

  // get items type of Array
  if (ASTMatch.isArray(type)) return getTypeChildren(type.items);
};

const renderVariable = (variable: BaseVariableField) => ({
  title: variable.meta?.title,
  key: variable.key,
  // Only Object Type can drilldown
  children: getTypeChildren(variable.type).map(renderVariable),
});

// ....

```
